---
title: "Import from / Export to JS"
description: "Importing / exporting JS module content in ReScript"
canonical: "/docs/manual/import-from-export-to-js"
section: "JavaScript Interop"
order: 7
---

# Import from/Export to JS

You've seen how ReScript's idiomatic [Import & Export](./import-export.mdx) works. This section describes how we work with importing stuff from JavaScript and exporting stuff for JavaScript consumption.

If you're looking for react-specific interop guidance, check out the [React JS Interop guide](../react/import-export-reactjs.mdx).

**Note**: due to JS ecosystem's module compatibility issues, our advice of keeping your ReScript file's compiled JS output open in a tab applies here **more than ever**, as you don't want to subtly output the wrong JS module import/export code, on top of having to deal with Babel/Webpack/Jest/Node's CommonJS \<-> JavaScript module compatibility shims.

In short: **make sure your bindings below output what you'd have manually written in JS**.

## Output Format

We support 2 JavaScript import/export formats:

- JavaScript module: `import * from 'MyReScriptFile'` and `export let ...`.
- CommonJS: `require('myFile')` and `module.exports = ...`.

The format is [configurable in via `rescript.json`](./build-configuration.mdx#package-specs).

## Import From JavaScript

### Import a JavaScript Module's Named Export

Use the `module` [external](./external.mdx):

<CodeTab labels={["ReScript", "JS Output (Module)", "JS Output (CommonJS)"]}>

```res example
// Import nodejs' path.dirname
@module("path") external dirname: string => string = "dirname"
let root = dirname("/User/github") // returns "User"
```

```js
import * as Path from "path";
var root = Path.dirname("/User/github");
```

```js
var Path = require("path");
var root = Path.dirname("/User/github");
```

</CodeTab>

Here's what the `external` does:

- `@module("path")`: pass the name of the JS module; in this case, `"path"`. The string can be anything: `"./src/myJsFile"`, `"@myNpmNamespace/myLib"`, etc.
- `external`: the general keyword for declaring a value that exists on the JS side.
- `dirname`: the binding name you'll use on the ReScript side.
- `string => string`: the type signature of `dirname`. Mandatory for `external`s.
- `= "dirname"`: the name of the variable inside the `path` JS module. There's repetition in writing the first and second `dirname`, because sometime the binding name you want to use on the ReScript side is different than the variable name the JS module exported.

### Import a JavaScript Module As a Single Value

By omitting the string argument to `module`, you bind to the whole JS module:

<CodeTab labels={["ReScript", "JS Output (Module)", "JS Output (CommonJS)"]}>

```res example
@module external leftPad: (string, int) => string = "./leftPad"
let paddedResult = leftPad("hi", 5)
```

```js
import * as LeftPad from "./leftPad";
var paddedResult = LeftPad("hi", 5);
```

```js
var LeftPad = require("./leftPad");
var paddedResult = LeftPad("hi", 5);
```

</CodeTab>

Depending on whether you're compiling ReScript to JavaScript module or CommonJS, **this feature will generate subtly different code**. Please check both output tabs to see the difference. The JavaScript module output here would be wrong!

### Import an `default` Export

Use the value `default` on the right hand side:

<CodeTab labels={["ReScript", "JS Output (Module)"]}>

```res example
@module("./student") external studentName: string = "default"
Console.log(studentName)
```

```js
import Student from "./student";
var studentName = Student;
```

</CodeTab>

### Use Import Attributes

**Since 11.1**

[Import attributes](https://github.com/tc39/proposal-import-attributes) can be used in ReScript, as long as ReScript is configured to output JavaScript module. You do that by passing configuration to the `@module` attribute:

<CodeTab labels={["ReScript", "JS Output (Module)"]}>
```rescript
@module({from: "./myJson.json", with: {type_: "json", \"some-exotic-identifier": "someValue"}})
external myJson: JSON.t = "default"

Console.log(myJson)

````

```javascript
import MyJsonJson from "./myJson.json" with {"type": "json", "some-exotic-identifier": "someValue"};

var myJson = MyJsonJson;

console.log(myJson);
````

</CodeTab>

This above imports the local `./myJson.json` file, adding import attributes.

This is how it works:

1. Instead of passing a string or tuple to `@module`, pass a record.
2. This record should have a `from` key. The value of that is where you want the module to be imported from (just like the regular string to `@module` is).
3. It should also have a `with` key, with another record where you put all the import attributes you want emitted.

Notice `\"some-exotic-identifier"` - you'll need to escape any key that's not a valid ReScript record key.
Also notice `type_`. Since `type` is a reserved keyword in ReScript, you can use `type_` instead. It will be output as `type` in the JavaScript code.

## Dynamic Import

Leveraging JavaScript's [dynamic `import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) to reduce bundle size and lazy load code as needed is easy in ReScript. It's also a little bit more convenient than in regular JavaScript because you don't need to keep track of file paths manually with ReScript's module system.

### Dynamically Importing Parts of a Module

Use the `import` function to dynamically import a specific part of a module. Put whatever `let` binding you want to import in there, and you'll get a `promise` back resolving to that specific binding.

Let's look at an example. Imagine the following file `MathUtils.res`:

```rescript
let add = (a, b) => a + b
let sub = (a, b) => a - b
```

Now let's dynamically import the add function in another module, e.g. `App.res`:

<CodeTab labels={["ReScript", "JS Output (Module)"]}>
```rescript
// App.res
let main = async () => {
  let add = await import(MathUtils.add)
  let onePlusOne = add(1, 1)

Console.log(onePlusOne)
}

````
```javascript
async function main() {
  var add = await import("./MathUtils.mjs").then(function(m) {
    return m.add;
  });

  var onePlusOne = add(1, 1);
  console.log(onePlusOne);
}
````

</CodeTab>

### Dynamically Importing an Entire Module

The syntax for importing a whole module looks a little different, since we are operating on the module syntax level; instead of using `import`, you may simply `await` the module itself:

<CodeTab labels={["ReScript", "JS Output (Module)"]}>
```rescript
// App.res
let main = async () => {
  module Utils = await MathUtils

let twoPlusTwo = Utils.add(2, 2)
Console.log(twoPlusTwo)
}

````
```javascript
async function main() {
  var Utils = await import("./MathUtils.mjs");

  var twoPlusTwo = Utils.add(2, 2);
  console.log(twoPlusTwo);
}
````

</CodeTab>

## Export To JavaScript

### Export a Named Value

As mentioned in ReScript's idiomatic [Import & Export](./import-export.mdx), every let binding and module is exported by default to other ReScript modules (unless you use a `.resi` [interface file](./module.mdx#signatures)). If you open up the compiled JS file, you'll see that these values can also directly be used by a _JavaScript_ file too.

### Export a `default` Value

If your JS project uses JavaScript module, you're likely exporting & importing some default values:

```js
// student.js
export default name = "Al";
```

```js
// teacher.js
import studentName from "student.js";
```

A JavaScript default export is really just syntax sugar for a named export implicitly called `default` (now you know!). So to export a default value from ReScript, you can just do:

<CodeTab labels={["ReScript", "JS Output (Module)", "JS Output (CommonJS)"]}>

```res example
// ReScriptStudent.res
let default = "Bob"
```

```js
var $$default = "Bob";

exports.$$default = $$default;
exports.default = $$default;
// informal transpiler-compatible marker of a default export compiled from JavaScript module
exports.__esModule = true;
```

```js
var $$default = "Bob";

export { $$default, $$default as default };
```

</CodeTab>

You can then import this default export as usual on the JS side:

```js
// teacher2.js
import studentName from "ReScriptStudent.js";
```

If your JavaScript's default import is transpiled by Babel/Webpack/Jest into CommonJS `require`s, we've taken care of that too! See the CommonJS output tab for `__esModule`.
